/**************************************************************************************************
  Filename:       logic_handler.c
  Revised:        $Date: 2014-12-08 10:20:18 +0800 (Fri, 04 Apr 2014) $
  Revision:       $Revision: 10001 $

  Description:    This file contains the main logic of the whole system.
**************************************************************************************************/

#include "logic_handler.h"
#include "hal_mpu.h"

#define CGET 0xEE
#define CFUN 0xDD
#define CSET 0xCC

#define INVALID_CONNHANDLE                    0xFFFF
extern volatile DataPage _dataPg;
extern volatile UserPage _userPg;
extern volatile SecuPage _secuPg;
extern volatile TimePage _timePg;
extern volatile SettingsPage _settingsPg;
extern volatile HardWareInfo _hardPg;
extern volatile UTCTime __currentTimeUnix;

extern volatile uint32 __currentAddr;
extern volatile uint32 __iterAddr;
extern volatile uint8 __realtimeFlag;
extern volatile uint8 __eraseFlag;
extern volatile uint8 __save2MemFlag;

extern uint8 global_stack[264];
extern uint8 global_string[13];
extern uint8 global_setting_argv[2];
extern volatile uint8 global_statck_busy;

bStatus_t saveHandler(UnitData unit);
bStatus_t timeHandler(UnitData unit);

void notify(uint8 *string);


bStatus_t dataHandler(UnitData unit)
{
  // __realtimeFlag = OPEN_REALTIME;
  dbg("hi\n");
  if (isConnected() && __realtimeFlag == OPEN_REALTIME)
  {	// Todo : connected
    uint8 stringx[13] =  {0,0,0,0, \
                          0,0,0,0, \
                          0,0,0,0, \
                          0};
    uint8 datalen = UD_toString(unit,stringx);
    // dbg("%x,%x,%x,%x,%x,%x,%x,%x\n",string[0],string[1],string[2],string[3],string[4],string[5],string[6],string[7]);
    uint16 gapConnHandle;
    GAPRole_GetParameter( GAPROLE_CONNHANDLE, &gapConnHandle );
   // bStatus_t ret = SUCCESS;
    dbg("hello2\n");
    bStatus_t ret = DataPack_Notify(gapConnHandle,stringx);
    dbg("hello3\n");
    if (ret == SUCCESS)
    {
      dbg("\n notify success");
      // todo set Flag    
    }else{
      dbg("\n notify FAILURE:%x",ret);

      return saveHandler(unit);
    }
  }
  else  // NOT Connected
  {
    //dbg("NOT Connected\n");
    // Todo : Not Connected Or Not Send success
    return saveHandler(unit);
    //bsp_dataPg2Mem();   //write to flash every Flash Update
  }
  return SUCCESS;
}

bStatus_t saveHandler(UnitData unit)
{
  if(isFlashBusy())
  {
    return FAILURE;
  }
  __currentAddr = UD_write(unit,__currentAddr);
  _dataPg.datasize ++;
  _dataPg.endAddr = __currentAddr - UD_getLength(unit.meta);
  _dataPg.newAddr = __currentAddr;
  _dataPg.lastUpdateTime = __currentTimeUnix;
  return SUCCESS;
}

bStatus_t syncHandler(uint8 taskID,uint8 suid)     //Todo : Put once connected    
{
  // WAIT_MS(1000);
 // HAL_ENTER_ISR();
  dbg("sync1 status:%x::\n",_dataPg.status);
  uint8 _msg_buffer_not_avail = 0;
  if(  _dataPg.status == META_DATA_NORMAL ||  _dataPg.status == META_DATA_INTERRUPT)
  {
    uint32 _curAddr_ = __currentAddr;
    uint32 _endAddr_ = _dataPg.endAddr;
    uint32 _startAddr_ = _dataPg.startAddr;
    
    dbg("001\n");
    if ( __iterAddr < _curAddr_)
    {dbg("002\n");
      if (isConnected())
      {dbg("003\n");
        if (isFlashBusy())
        {dbg("004\n");
          return MSG_BUFFER_NOT_AVAIL;      //return if flash is busy,wait for next.
        }
        //UD_read(UnitData *unit,uint32 addr)
        UnitData unit;
        uint32 addr = UD_read(&unit,__iterAddr);
        uint32 addr0 = (addr & 0xFF);
        uint32 addr1 = (addr & 0xFF00) >> 8;
        uint8 string[13] =  {0xF0,suid,addr0,addr1, \
                             0   ,0   ,0    ,0    , \
                             0   ,0   ,0    ,0    , 0};   //0xF0 Upload data
        uint8 datalen = UD_toString(unit,string+4);

        dbg("\r\n\n\titerAddr:%08lx\n\n",__iterAddr);
        dbg("%x,%x,%x,%x,%x,%x,%x,%x\n",string[0],string[1],string[2],string[3],string[4],string[5],string[6],string[7]);

        uint16 connHandle = INVALID_CONNHANDLE;
        GAPRole_GetParameter( GAPROLE_CONNHANDLE, &connHandle );
        bStatus_t ret = DataPack_Notify(connHandle,string);

        dbg("iterAddr:%x::::\n",ret);
        if (ret == SUCCESS)
        {
          __iterAddr = addr;
          if (__iterAddr >= _curAddr_)
          {
            _dataPg.status = META_DATA_SYNCDONE;
          }else{
            _dataPg.status = META_DATA_NORMAL;
            osal_start_timerEx(taskID,MWH_SYNC_DATA_EVT,30);  
          }
        }
        else
        {
          dbg("From1 Here\n");
          _dataPg.status = META_DATA_INTERRUPT;      // need try once more 
          // break;
          if (ret == MSG_BUFFER_NOT_AVAIL)
          {
            _msg_buffer_not_avail  = 1;
          }
        }
      }
      else
      {
        if (__iterAddr > _startAddr_ && (__iterAddr < _endAddr_ - 5) )
        {
          dbg("Fromx Here\n");
          _dataPg.status = META_DATA_INTERRUPT;
          // break;
        }else{
          // ignore last 5
          _dataPg.status = META_DATA_SYNCDONE;
          // __iterAddr = __currentAddr;
          // _dataPg.status = META_DATA_NORMAL;
        }
      }
    }
  }

 // HAL_EXIT_ISR(); 
  dbg("sync2 status:%x::\n",_dataPg.status);
  if ( _dataPg.status == META_DATA_SYNCDONE )
  {
    //HAL_ENTER_ISR();
    //INIT addr
    _dataPg.status = META_DATA_NORMAL;
    __currentAddr = DATA_START;
    __iterAddr = DATA_START;
    _dataPg.iterAddr = __iterAddr;
    _dataPg.startAddr = DATA_START;
    _dataPg.endAddr = DATA_START;
    _dataPg.newAddr = DATA_START;
    _dataPg.lastUpdateTime = __currentTimeUnix;
    _dataPg.lastSyncTime = __currentTimeUnix;
    
    if(isFlashBusy())
    {
      osal_start_timerEx( taskID, MWH_FLASH_UPDATE_EVT, 500 );
      dbg("\n\n\\ status save timer on");
    }
    else
    {
      bsp_dataPg2Mem();
      dbg("\n\nstatus has saved!\n\n");
    }
    osal_stop_timerEx(taskID,MWH_SYNC_DATA_EVT);
    //Erase
    //for (uint8 ite = 0; ite < DATA_SECTOR_COUNT; ++ite)
    {
        __eraseFlag = 0;
        DBSectorErase(dataSectorAddrs[__eraseFlag],NONBLOCK);
        /********************
         * No need for erase all data!
         * We use the method of erase when need next page
         * @code  osal_start_timerEx( taskID, MWH_SECTOR_ERASE_EVT, ERASE_INTVAL );
        ********************/
    }
    //HAL_EXIT_ISR();
    return SUCCESS;
  }
  dbg("sync3 status:%x::\n",_dataPg.status);
  if ( _dataPg.status == META_DATA_INTERRUPT )
  {
     osal_stop_timerEx(taskID,MWH_SYNC_DATA_EVT);
     //write to memory
     //HAL_ENTER_ISR();
     _dataPg.iterAddr = __iterAddr;
     bsp_dataPg2Mem();

     if (_msg_buffer_not_avail == 1)
     {
        osal_start_timerEx(taskID,MWH_SYNC_DATA_EVT,2000);
        _msg_buffer_not_avail  = 0;
     }
     
     //HAL_EXIT_ISR();
    return SUCCESS;
  }
 
  return FAILURE;
  //Todo  Iterrupted? 
  //      Read data from IterAddr 
  //      Notify calculate 1.3KB/s   13Byte * 100    Notify <= 100 per second,WAIT_MS(N)  N >= 10
  
  //      Update Meta Data
  //      Erase sector from 0B to 15
  
  //      if interrupted update Meta data iterAddr

  //   Change daycount to interrupted?
}

void motionProcess()
{

  bool shake = IsDeviceShaking();
}

bStatus_t motionHandler(uint8 taskID,uint8 paramID)
{

  switch(paramID)
  {
    // case MOTION_SHAKE_HARD:
    //   osal_start_timerEx( taskID, MWH_START_DEVICE_EVT, 1000 );          //start delay 1000 ms
    //   BattLED_ON();
    //   WAIT_MS(500);
    //   BattLED_OFF();
    //   SignalLED_ON();
    //   WAIT_MS(500);
    //   SignalLED_OFF();
    //   WarnLED_ON();
    //   WAIT_MS(500);
    //   WarnLED_OFF();
    //   break;
    case MOTION_TAP:
      //SetParamter(on)
      break;
    case MOTION_TURN:

      break;
    case MOTION_CLIMB:
    
      break;
    case MOTION_WALK:
    
      break;
    // case MOTION_RUN:
    
    //   break;
    // case MOTION_JUMP:

    //   break;
    default:

      break;
  }
  return FAILURE;
}
/****
#define SET_CHILDNAME 0x01
#define SET_BIRTHTIME 0x02
#define SET_ALLERGY 0x03
#define SET_TOY 0x04
#define SET_FOOD 0x05
#define SET_MNAME 0x06
#define SET_MPHONE 0x07
#define SET_FNAME 0x08
#define SET_FPHONE 0x09
#define SET_POSITION 0x0A
#define SET_USERNAME 0x0B
#define SET_PASSWORD 0x0C
#define SET_ADDRESS 0x0D

*****/
#define NELEMS(x)  (sizeof(x) / sizeof(x[0]))
void assembleSetting(uint8 *string,uint8 partNo,volatile uint8 *dst)
{
  if (partNo == 0 )
  {
     VOID osal_memset((uint8 *)dst,0,NELEMS(dst));
  }
  VOID osal_memcpy((uint8 *)(dst + partNo * SET_DATA_LEN), string + 1 ,SET_DATA_LEN);
}
CmdReg *cmdhead;
CmdReg *lastcmd;
PACKHEAD phx;

void CmdInit(void)
{
  cmdhead = NULL;
  
}
void RegCMD(uint8 uid,uint8 len,uint8 setting_type)
{
  CmdReg *nCmd;
  nCmd = (CmdReg *)osal_mem_alloc(sizeof(CmdReg));
  nCmd->uid = uid;
  nCmd->len = len;
  nCmd->pos = 0;
  uint8 need_len = getPointerViaSettingType(setting_type,nCmd->data);
  if (NULL == cmdhead)
  {
    cmdhead = nCmd;
    lastcmd = cmdhead;
  }else{
    lastcmd->next = nCmd;
    nCmd->next = NULL;
    lastcmd = lastcmd->next;
  }
}
#define FUNC_COMMAND  0x00
#define USE_RECV_ADDR 0x01

uint8 getPointerViaSettingType(uint8 setting_type,volatile uint8 *data)
{
  switch(setting_type)
  {
    case CFUN_LED1:
    case CFUN_LED2:
    case CFUN_LED3:
    case CFUN_STOP_SYNC:
    case CFUN_SAVE_CURRENT:
    case CFUN_UPDATE_ROM:
    case CFUN_DISABLE_ROM:
    case CFUN_REBOOT:
      data = NULL;
      return FUNC_COMMAND;
    //GET
    case CGET_ITERRUPT_ADDR:
      data = (uint8 volatile *)&__currentAddr;
      return 4;
    case CGET_FIRMWAREVER:
      data = (uint8 volatile *)&_hardPg.firmversion;
      return 4;
    case CGET_DEVICEID:
      data = (uint8 volatile *)&_hardPg.deviceID;
      return 4;
    case CGET_VERSION:
      data = (uint8 volatile *)&_hardPg.version;
      return 4;
    // PureData Set
    case CDAT_CHILDNAME:
      data = _userPg.name;
      return 24;
    case CDAT_BIRTHTIME:
      data = (uint8 volatile *)&_userPg.age;
      return 4;
    case CDAT_ALLERGEY:
      data = _userPg.allergy;
      return 56;
    case CDAT_TOY:
      data = _userPg.toy;
      return 84;
    case CDAT_FOOD:
      data = _userPg.food;
      return 84;
    case CDAT_MNAME:
      data = _secuPg.motherName;
      return 24;
    case CDAT_MPHONE:
      data = _secuPg.motherPhone;
      return 12;
    case CDAT_FNAME:
      data = _secuPg.fatherName;
      return 24;
    case CDAT_FPHONE:
      data = _secuPg.fatherPhone;
      return 12;
    case CDAT_POSTION:
      data = _settingsPg.position;
      return 8;
    case CDAT_USERNAME:
      data = _secuPg.username;
      return 12;
    case CDAT_PASSWORD:
      data = _secuPg.password;
      return 36;
    case CDAT_ADDRESS:
      data = _secuPg.address;
      return 96;
    // Value Set
    case CVAL_DIAPER_INTERVAL:
      data = (uint8 volatile *)&_settingsPg.diaper_interval;
      return 4;
    case CVAL_DIAPER_NUMBER:
      data = (uint8 volatile *)&_settingsPg.diaper_number;
      return 4;
    case CVAL_DIAPER_FACTOR:
      data = (uint8 volatile *)&_settingsPg.diaper_factor;
      return 4;
    case CVAL_SLEEP_INTERVAL:
      data = (uint8 volatile *)&_settingsPg.sleep_interval;
      return 4;
    case CVAL_SLEEP_FACTOR:
      data = (uint8 volatile *)&_settingsPg.sleep_factor;
      return 4;
    case CVAL_MOTION_INTERVAL:
      data = (uint8 volatile *)&_settingsPg.motion_interval;
      return 4;
    case CVAL_MOTION_FACTOR:
      data = (uint8 volatile *)&_settingsPg.motion_factor;
      return 4;
    case CVAL_BATT_INTERVAL:
      data = (uint8 volatile *)&_settingsPg.batt_interval;
      return 4;
    case CVAL_BATT_FACTOR:
      data = (uint8 volatile *)&_settingsPg.batt_factor;
      return 4;
    case CVAL_TIME:
      data = (uint8 volatile *)&_timePg.time;
      return 4;
    case CVAL_INTERVAL:
      data = (uint8 volatile *)&_settingsPg.intervalTime;
      return 4;

    case CPAG_DATAINFO:
      data = (uint8 volatile *)&_dataPg.datasize;
      return PAGE_DATAINFO_LENGTH;
    case CPAG_USERINFO:
      data = _userPg.name;
      return PAGE_USERINFO_LENGTH;
    case CPAG_SECUINFO:
      data = _secuPg.username;
      return PAGE_SECUINFO_LENGTH;
    case CPAG_TIMEINFO:
      data = (uint8 volatile *)&_timePg.time;
      return PAGE_TIMEINFO_LENGTH;
    case CPAG_SETTINGS:
      data = (uint8 volatile *)&_settingsPg.intervalTime;
      return PAGE_SETTINGS_LENGTH;
    case CPAG_HARDWARE_INFO:
      data = &_hardPg.flag;
      return PAGE_HARDINFO_LENGTH;
    
    case CFLA_APPEND:
    case CFLA_DELETE:
    case CFLA_CHANGE:
    case CFLA_SELECT:
      data = NULL;
      return USE_RECV_ADDR;
    default:
      data = NULL;
      
  }
  return 0xFF;
}
uint8 UnregCMD(uint8 uid)
{
  CmdReg *c1;
  CmdReg *c2;
  c1 = cmdhead;
  c2 = c1;
  if (c1 == NULL)
  {
    return 0;
  }
  while(c1)
  {
    if (c1->uid == uid)
    {
      if (c1 == cmdhead)
      {
        cmdhead = c1->next;
      }else{
        c2->next = c1->next;
      }
      osal_mem_free((void *)c1);
      return 1;
    }
    c2 = c1;
    c1 = c1->next;
  }
  return 0;
}
uint8 findbyUid(uint8 uid,CmdReg *cmd)
{
  CmdReg *c1;
  // CmdReg *c2;
  c1 = cmdhead;
  if (c1 == NULL)
  {
    return 0;
  }
  while(c1){
    if (c1->uid == uid)
    {
      // data = c1->data;
      cmd = c1;
      return 1;
    }
    c1 = c1->next;
  }
  return 0;
  // uint8 uid;
  // uint8 pos;
  // uint8 len;
  //  method
  // uint8 *data;
  // struct _list_data *next;
}
bStatus_t infoHandler(uint8 taskID,uint8 *string)
{
  if (string[0] == 0xB5)
  {
    // fill packhead
    PACKHEAD ph;
    ph.taskID = taskID;
    ph.meta = string[0];
    ph.setting_type = string[1];
    ph.method = string[2];
    ph.len = string[3];
    ph.randid = string[4];
    for (uint8 i = 0; i < 8; ++i)
    {
      ph.data[i] = string[4+i];
    }

    // register now head \ id \ recv or send flag
    uint8 *pdata;
    uint8 len = getPointerViaSettingType(ph.setting_type,pdata);

    // here to determine!!!
    if (pdata == NULL && len == USE_RECV_ADDR)
    {
      cmd_crud(ph);
    }

    if (pdata == NULL && len == FUNC_COMMAND)
    {
      execute_funcmd(ph);
    }

    if (ph.method == CGET)
    {
      uint8 retData[12] = {0x5B,ph.randid};
      uint8 pdata_len  = NELEMS(pdata);
      for (uint8 iter = 0; iter < len; iter = iter + 8)
      {
        retData[2] = (iter >> 8) & 0xFF;
        retData[3] = iter & 0xFF;
        for (int kter = 0; kter < 8; ++kter)
        {
          if (iter+kter > pdata_len)
          {
            retData[kter+4] = 0;
          }
          else
          {
            retData[kter+4] = pdata[iter+kter];
          }
        }
        uint16 gapConnHandle;
        GAPRole_GetParameter( GAPROLE_CONNHANDLE, &gapConnHandle );
        bStatus_t ret = DataPack_Notify(gapConnHandle,retData);
        if (ret == SUCCESS)
        {
          dbg("\n warning notify success");
          return SUCCESS;
        }
        else{
          // just do nothing ~ sorry to do this   ;P
          // will do next loop?
        }
      }
      // for xxx 
      //    asssemble
      //    Notify
      //osal_start_timerEx(SENDDATA)
    }
    if (ph.method == CFUN)
    {
      execute_funcmd(ph);
      // do something
    }
    if (ph.method == CSET)
    {
      
      RegCMD(ph.randid,ph.len,ph.setting_type);//Register
    }
  }
  if (string[0] == 0x5B)
  {
    uint8 *pdata;
    CmdReg cmd;
    uint8 ret = findbyUid(string[1],&cmd);// find address
    if (string[2] == 0xFF && string[3] == 0xFF)
    {
      UnregCMD(string[1]);// address remove
      return SUCCESS;
    }
    uint16 no = string[2] << 8 + string[3];
    if (ret)// check id and find head's setting
    {
      for (uint8 iter = 0; iter < 8; ++iter)
      {
        if ( no*8 + iter < cmd.len)
        {
           cmd.data[no*8 + iter] = string[iter + 4];// osal_memcpy_ address = xxxx
        }
      }
    }
    else{
      // not find && let it go
    }
   
  }else{

  }
  return SUCCESS;
}
void cmd_crud(PACKHEAD ph)
{
  uint32 addr = BUILD_UINT32(ph.data[0],ph.data[1],ph.data[2],ph.data[3]);
  uint8 data[4] = {ph.data[4],ph.data[5],ph.data[6],ph.data[7]};
  uint8 erase[4] = {0,0,0,0};
  switch(ph.setting_type)
  {
    case CFLA_APPEND:
      bsp_write(addr,data,4);
      break;
    case CFLA_DELETE:
      bsp_write(addr,erase,4);
      break;
    case CFLA_CHANGE:
      bsp_write(addr,data,4);
      break;
    case CFLA_SELECT:
      {
        uint32 len = BUILD_UINT32(ph.data[4],ph.data[5],ph.data[6],ph.data[7]);
        uint8 tmpdata[13]={0x5B,ph.randid};
        uint8 k=0;
        for (uint32 iter = 0; iter < len; ++iter)
        {
          addr = bsp_read8b(addr,&tmpdata[4+k]);
          k++;
          if (iter % 7 == 0 && iter != 0)
          {
            uint8 no = (iter/7);
            tmpdata[2] =  (no >> 8) & 0xFF;
            tmpdata[3] = no & 0xFF;
            notify(tmpdata);
            k=0;
          }
        }
        break;
      }
    default:
    break;
  }
}
void execute_funcmd(PACKHEAD ph)
{
  switch(ph.setting_type)
  {
    case CFUN_LED1:
    {
      WarnLedBlink();
      break;
    }
    case CFUN_LED2:
    {
      SignalLedBlink();
      break;
    }
    case CFUN_LED3:
    {
      BattLedBlink();
      break;
    }
    case CFUN_STOP_SYNC:
    {
      osal_stop_timerEx(ph.taskID,MWH_SYNC_DATA_EVT);
      break;
    }
    case CFUN_SAVE_CURRENT:
    {
      bsp_dataPg2Mem();
      // bsp_userPg2Mem();
      // bsp_secuPg2Mem();
      bsp_timePg2Mem();
      bsp_setPg2Mem();
      // bsp_hwPg2Mem();
      break;
    }
    case CFUN_UPDATE_ROM:
    {
      break;
    }
    case CFUN_DISABLE_ROM:
    {
      break;
    }
    case CFUN_REBOOT:
    {
      break;
    }
    default:
    break;
  }
}
void notify(uint8 *string)
{
    uint16 gapConnHandle;
    GAPRole_GetParameter( GAPROLE_CONNHANDLE, &gapConnHandle );
    bStatus_t ret = DataPack_Notify(gapConnHandle,string);
    if (ret == SUCCESS)
    {
      dbg("\n notify success");
      // todo set Flag    
    }
    else
    {
      dbg("\n notify FAILURE:%x",ret);
      // return saveHandler(unit);
    }
}
// void prepend(uint8 *string,uint8 pre,uint8 *buf,uint8 length)
// {
//   global_string[0] = pre;
//   osal_memcpy(global_string+1,buf,length);

// }
// void prepend12(uint8 *string,uint8 pre,uint8 *buf)
// {
//   prepend(string,pre,buf,12);
// }
void settingNotify(uint8 taskID,uint8 *buf,uint8 len,uint8 datatype)
{
  uint16 connHandle = INVALID_CONNHANDLE;
  static uint8 itt = 0;
  GAPRole_GetParameter( GAPROLE_CONNHANDLE, &connHandle );
  if(connHandle != INVALID_CONNHANDLE)
  {
    global_string[0] = UPLOAD_PURE_DATA | datatype;
    osal_memcpy(global_string+1,buf+itt*12,12);

    bStatus_t ret = DataPack_Notify(connHandle,global_string);

    if (ret == SUCCESS)
    {
      dbg("\nNotify for %d\n\n",itt);
      if (itt < len - 1 )
      {
        itt++;
        global_setting_argv[0] = len;
        global_setting_argv[1] = datatype;
        osal_start_timerEx(taskID,MWH_SETTING_NOTIFY_EVT,100);
      }
      else if (itt == len - 1)
      {
        itt = 0;     
        osal_stop_timerEx(taskID,MWH_SETTING_NOTIFY_EVT);
        uint8 ack = 0x98; // SETTING_NOTIFY_DONE
        Data_SetParameter(DATA_ACK,1,&ack);
        global_statck_busy = 0;
      }
    }else{
      //Exception: Connection Error;
      itt = 0;
      osal_stop_timerEx(taskID,MWH_SETTING_NOTIFY_EVT);
      global_statck_busy = 0;
    }
  }
}

bStatus_t startSendSetting(uint8 taskID,uint8 list)
{
  switch(list)
  {
    case DATACTRL_GET_USERPAGE:
      {
        global_statck_busy = 1;
        osal_memcpy(global_stack,(UserPage *)&_userPg,sizeof(_userPg));
        settingNotify(taskID,global_stack,22,PURE_DATA_USERINFO);
      }
    break;
    case DATACTRL_GET_SECUPAGE:
      {
        global_statck_busy = 1;
        osal_memcpy(global_stack,(SecuPage *)&_secuPg,sizeof(_secuPg));
        settingNotify(taskID,global_stack,18,PURE_DATA_SECUINFO);
      }
    break;
    case DATACTRL_GET_SETTINGPAGE:
      {
        global_statck_busy = 1;
        osal_memcpy(global_stack,(SettingsPage *)&_settingsPg,sizeof(_settingsPg));
        settingNotify(taskID,global_stack,8,PURE_DATA_SETTINGINFO);
      }
      break;
    default:
      // not implement now

    break;
  }
  return SUCCESS;
}


// rev string handler
bStatus_t udStrHandler(uint8 *string)
{
  UnitData ud;
  ud.meta = string[0];
//  ud.time = BUILD_UINT32(string[1],string[2],string[3],string[4]);
  uint8 datalen = getUDLen(ud.meta);
  for (int8 i = datalen - 1; i >=0 ; --i)
  {                 //5 + (datalen -1 -i)
    ud.data[i] = string[4 + datalen - i] ;    
    //MSB is the last one,For instance
    //  arr[3]    arr[2]    arr[1]    arr[0]
    //  0x33221100
  }
  bStatus_t ret = SUCCESS;
  switch(ud.meta & UDTMASK)
  {
    case UDTSets:
      //todo receive humi level\temp level\batt level
      break;
    case UDTLeds:
      
      break;
    case UDTTime:
      //47000000001C1d89cf
      ret = timeHandler(ud);
      if (ret != SUCCESS)
      {
        return FAILURE;
      }
      break;
    case UDTWarn:
        
      break;
    default:
      
      break;
  }
  return SUCCESS;
}

bStatus_t timeHandler(UnitData unit)
{
  if (unit.meta & UDTTime == UDTTime)
  {
    uint32 clocktime = BUILD_UINT32(unit.data[0],unit.data[1],unit.data[2],unit.data[3]); 
    osal_setClock(clocktime);
    _timePg.time = __currentTimeUnix;
    bsp_timePg2Mem();
    return SUCCESS;
  }
  return FAILURE;
}

uint16 get_middle_one(uint16 *buf)
{
  return ( buf[0] >= buf[1] ?    \
         ( buf[2] >= buf[0] ? buf[0] : (buf[1] > buf[2] ? buf[1] : buf[2] ) ) : \
         ( buf[0] >= buf[2] ? buf[0] : (buf[1] > buf[2] ? buf[2] : buf[1] ) )
         );
}

uint8 HumiProcess(uint16 humidata,uint16 tempdata)
{
  uint8 level = 10;  
  double humi_level = calcHumRel(humidata);
  double temp_level = calcHumTmp(tempdata);
  //Todo:  Level can be set from Android.

  if (humi_level >= level)   //time write to page
  {
    
    // SignalLedBlink();
    return NEED_CONFIRM_TURN_ON;

  }else
  {
    // SignalLedStop();
    return NEED_CONFIRM_TURN_OFF;
  }
   
}

// #define POSTURE_UP      0x01
// #define POSTURE_DOWN    0x02
// #define POSTURE_LEFT    0x03
// #define POSTURE_RIGHT   0x04
void SleepProcess(uint8 *result)
{
  
  //float Eulerangles[3];
  //getYawPitchRoll(Eulerangles);          
  //dbg("angle is-----%f-------%f--------%f-------\n\n",Eulerangles[0],Eulerangles[1],Eulerangles[2]); 
}

void BattHandler(void)
{
  bStatus_t ret = Batt_MeasLevel();
  if (ret == BATT_LEVEL_INDANGER)
  {
    BattLedBlink();
    broadcastHanler(BC_BATT_EVENT);
  }else{
    BattLedStop();
  }
}


bStatus_t broadcastHanler(uint8 paramID)
{
  if (!isConnected())
  {
    return FAILURE;
  }
  UnitData unit;
  uint8 buf[2];

  switch(paramID)
  {
    case BC_HUMI_EVENT:
    
      buf[0] = 0x01;    //Priority
      buf[1] = 0x01;    // type
    break;
    case BC_BATT_EVENT:
      buf[0] = 0x02;    //Priority
      buf[1] = 0x02;    // type
    break;
    case BC_POST_EVENT:

      return SUCCESS;
    break;
    default:
    break;
  }
  
  // UDWarnInit(&unit,buf);

  {    
    uint8 string[13] =  {0,0,0,0, \
                         0,0,0,0, \
                         0,0,0,0,0};
    uint8 datalen = UD_toString(unit,string);
    // dbg("%x,%x,%x,%x,%x,%x,%x,%x\n",string[0],string[1],string[2],string[3],string[4],string[5],string[6],string[7]);
    uint16 gapConnHandle;
    GAPRole_GetParameter( GAPROLE_CONNHANDLE, &gapConnHandle );
    bStatus_t ret = DataPack_Notify(gapConnHandle,string);
    if (ret == SUCCESS)
    {
      dbg("\n warning notify success");
      return SUCCESS;
    }
    else{
      // just do nothing ~ sorry to do this   ;P
    }

  }
  return FAILURE;
}

bStatus_t settingHandler(UnitData unit)
{
  return FAILURE;
}

bool isConnected(void)
{
  uint16 gapConnHandle;
  uint8 gapRoleStat;
  GAPRole_GetParameter( GAPROLE_CONNHANDLE, &gapConnHandle );
  GAPRole_GetParameter( GAPROLE_STATE , &gapRoleStat);
  if ( (gapRoleStat == GAPROLE_CONNECTED || gapRoleStat == GAPROLE_CONNECTED_ADV) && (gapConnHandle != INVALID_CONNHANDLE) )
  {
    dbg("is connected!\n\n");
    return true;
  }
  dbg("Not Connected\n\n");
  return false;
}

